package com.kzj.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.kzj.common.constant.GlobalConstant;
import com.kzj.common.exception.MyException;
import com.kzj.common.properties.NoteProperties;
import com.kzj.common.re.Result;
import com.kzj.common.util.CreateRandomName;
import com.kzj.common.util.SMSUtils;
import com.kzj.common.util.SMSUtils2;
import com.kzj.common.util.ValidateCodeUtils;
import com.kzj.domain.User;
import com.kzj.dao.UserDao;
import com.kzj.domain.dto.UserLoginDTO;
import com.kzj.domain.dto.UserRegisterDTO;
import com.kzj.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.concurrent.locks.ReadWriteLock;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author kzj
 * @since 2023-11-15
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserDao, User> implements UserService {
    @Autowired
    NoteProperties noteProperties;
    @Autowired
    SMSUtils2 smsUtils;
    @Override
    public Result register(UserRegisterDTO userRegisterDTO, HttpServletRequest request) {
        if(!userRegisterDTO.getPhone().matches(GlobalConstant.PHONE_REGEX))
        {
            Result.error(GlobalConstant.PHONE_FORMAT_ERROR);
        }
        User user=new User();
        user.setPhone(userRegisterDTO.getPhone());
        user.setPassword(DigestUtils.md5DigestAsHex(userRegisterDTO.getPassword().getBytes()));
        user.setUsername(CreateRandomName.getRandomEnglishName(8));
        save(user);
        return Result.success(GlobalConstant.USER_REGISTER_SUCCESS);
    }

    @Override
    public Result login(UserLoginDTO userLoginDTO,HttpServletRequest request) {
        if(!userLoginDTO.getPhone().matches(GlobalConstant.PHONE_REGEX))
        {
            return Result.error(GlobalConstant.PHONE_FORMAT_ERROR);
        }
        User user=null;
        if(userLoginDTO.getPassword()==null)
        {
            if(userLoginDTO.getCode()==null)
            {
                return Result.error(GlobalConstant.CODE_NOT_NULL);
            }
            String trueCode = (String)request.getSession().getAttribute(userLoginDTO.getPhone());
            String timestamp=(String)request.getSession().getAttribute("timestamp");
            if(trueCode==null||timestamp==null)
            {
                return Result.error(GlobalConstant.LOGIN_ERROR);
            }
            if(!trueCode.equals(userLoginDTO.getCode()))
            {
                return Result.error(GlobalConstant.CODE_ERROR);
            }
            LocalDateTime expirationTime = LocalDateTime.ofInstant(
                Instant.ofEpochMilli(Long.valueOf(timestamp)),
                ZoneId.systemDefault()
            ).plusMinutes(GlobalConstant.CODE_EXPIRATION_TIME);
            if(!LocalDateTime.now().isBefore(expirationTime))
            {
                return Result.error(GlobalConstant.CODE_EXPIRATION);
            }
            LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<>();
            lqw.eq(User::getPhone,userLoginDTO.getPhone());
            user = getOne(lqw);
            if(user==null)
            {
                user=new User();
                user.setPhone(userLoginDTO.getPhone());
                user.setUsername(CreateRandomName.getRandomEnglishName(GlobalConstant.CREATE_USER_DEFAULT_NAME_LEN));
                user.setGrade(GlobalConstant.CREATE_USER_DEFAULT_GRANGE);
                this.save(user);
            }
        }
        else{
            String password = DigestUtils.md5DigestAsHex(userLoginDTO.getPassword().getBytes());
            LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<>();
            lqw.eq(User::getPhone,userLoginDTO.getPhone());
            user = getOne(lqw);
            if(user==null)
            {
                user=new User();
                user.setPhone(userLoginDTO.getPhone());
                user.setPassword(password);
                user.setUsername(CreateRandomName.getRandomEnglishName(GlobalConstant.CREATE_USER_DEFAULT_NAME_LEN));
                user.setGrade(GlobalConstant.CREATE_USER_DEFAULT_GRANGE);
                this.save(user);
            }
            else if(!user.getPassword().equals(password))
            {
                throw new MyException(GlobalConstant.USER_PHONE_OR_PASSWORD_ERROR);
            }
        }
        request.getSession().setAttribute("userPhone",userLoginDTO.getPhone());
        user.setPassword(null);
        return Result.success(user);
    }

    @Override
    public Result getByPhone(String phone) {
        if(!phone.matches(GlobalConstant.PHONE_REGEX))
        {
            return Result.error(GlobalConstant.PHONE_FORMAT_ERROR);
        }
        LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<>();
        lqw.eq(User::getPhone,phone);
        User user = this.getOne(lqw);
        if(user==null)
        {
            return Result.error(GlobalConstant.USER_NOT_EXIST);
        }
        return Result.success(user);
    }

    @Override
    public Result updateByPhone(User user) {
        if(user.getGrade()!=null&&(user.getGrade()<1||user.getGrade()>6))
        {
            throw new MyException(GlobalConstant.GRADE_ERROR);
        }
        String password=user.getPassword();
        user.setPassword(DigestUtils.md5DigestAsHex(password.getBytes()));
        LambdaQueryWrapper<User> lqw=new LambdaQueryWrapper<>();
        lqw.eq(User::getPhone,user.getPhone());
        this.update(user, lqw);
        return Result.success();
    }

    @Override
    public Result sendMessageCode(String phone,HttpServletRequest request) {
        if(phone==null||!phone.matches(GlobalConstant.PHONE_REGEX))
        {
            return Result.error(GlobalConstant.PHONE_FORMAT_ERROR);
        }
        String code = ValidateCodeUtils.generateValidateCode(6).toString();
        request.getSession().setAttribute(phone,code);
        Long timestamp = System.currentTimeMillis();
        request.getSession().setAttribute("timestamp",timestamp.toString());
        log.info("用户:"+phone+"   验证码:"+code);
        smsUtils.sendMessage(phone,code);
        log.info("GlobalConstant.CODE_SEND_SUCCESS");
        return Result.success(GlobalConstant.CODE_SEND_SUCCESS);
    }
}
